package view;

import java.awt.Desktop;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.RowFilter;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;

import model.Contact;
import controller.Controller;
import javax.swing.JScrollBar;

@SuppressWarnings("serial")
public final class MainWindow extends JFrame implements MainWindowInterface {

    private JButton addButton;
    private JButton viewButton;
    private JButton modifyButton;
    private JButton deleteButton;
    private JTextField groupFilter;
    private JButton buttonFilter;
    private JList sections;
    private JButton cleanSections;

    private JScrollPane scrollpane;

    private JButton fileManager;

    private AddContactHandler addContactHandler;
    private ViewContactHandler viewContactHandler;
    private ModifyContactHandler modifyContactHandler;
    private DeleteContactHandler deleteContactHandler;

    private GroupFilterHandler groupFilterHandler;
    private SectionHandler sectionHandler;
    private ClearSelectionHandler clearSelectionHandler;

    private FileManagerHandler fileManagerHandler;

    private Controller controller;
    private MainWindow mainWindow;

    private JTable table;
    private DefaultTableModel tableModel;
    private Vector<Vector<Object>> tableData = new Vector<Vector<Object>>();
    private Vector<String> columnNames = new Vector<String>();

    public MainWindow() {
        super("Address Book.");

        this.mainWindow = this;
        this.addContactHandler = new AddContactHandler();
        this.viewContactHandler = new ViewContactHandler();
        this.modifyContactHandler = new ModifyContactHandler();
        this.deleteContactHandler = new DeleteContactHandler();
        this.groupFilterHandler = new GroupFilterHandler();
        this.sectionHandler = new SectionHandler();
        this.clearSelectionHandler = new ClearSelectionHandler();
        this.fileManagerHandler = new FileManagerHandler();

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLocationByPlatform(true);
        this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH);
        this.setResizable(true);
        JPanel abDisplay = this.generateDisplay();
        this.setContentPane(abDisplay);
        this.pack();
        this.setVisible(true);
    }

    private JPanel generateDisplay() {
        JPanel display = new JPanel();
        display.setLayout(new BoxLayout(display, BoxLayout.Y_AXIS));

        JPanel buttons = new JPanel();
        buttons.setLayout(new FlowLayout());
        buttons.setBorder(new CompoundBorder(new EmptyBorder(10, 10, 10, 10),
                new BevelBorder(1)));

        this.addButton = new JButton("New Contact.");
        addButton.addActionListener(addContactHandler);
        this.viewButton = new JButton("View Contact.");
        viewButton.addActionListener(viewContactHandler);
        this.modifyButton = new JButton("Modify Contact.");
        modifyButton.addActionListener(modifyContactHandler);
        this.deleteButton = new JButton("Remove Contact.");
        this.deleteButton.addActionListener(deleteContactHandler);

        buttons.add(addButton);
        buttons.add(viewButton);
        buttons.add(modifyButton);
        buttons.add(deleteButton);
        display.add(buttons);

        this.columnNames.add("First name");
        this.columnNames.add("Last name");
        this.columnNames.add("Personal address");
        this.columnNames.add("Company address");
        this.columnNames.add("Personal phones");
        this.columnNames.add("Company phones");
        this.columnNames.add("Web page");
        this.columnNames.add("E-mails");
        this.columnNames.add("Photo");
        this.columnNames.add("Others");
        this.columnNames.add("Groups");
        this.columnNames.add("Insert date");

        JPanel sectionsFrame = new JPanel();
        sectionsFrame.setLayout(new BoxLayout(sectionsFrame, BoxLayout.Y_AXIS));

        JLabel sectionsLabel = new JLabel(
                "Filter by the first letter of the last name:");
        sectionsLabel.setAlignmentX(CENTER_ALIGNMENT);
        sectionsFrame.add(sectionsLabel);
        String[] abcd = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
            "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
            "W", "X", "Y", "Z"};
        sections = new JList(abcd);
        ListSelectionModel sectionsSelModel = sections.getSelectionModel();
        sections.setSelectionMode(sectionsSelModel.SINGLE_SELECTION);
        sections.setVisibleRowCount(1);
        sections.setLayoutOrientation(JList.HORIZONTAL_WRAP);
        sections.addListSelectionListener(sectionHandler);
        sectionsFrame.add(sections);
        this.cleanSections = new JButton("Clean section");
        cleanSections.addActionListener(clearSelectionHandler);
        sectionsFrame.add(cleanSections);
        cleanSections.setAlignmentX(CENTER_ALIGNMENT);

        display.add(sectionsFrame);
        this.table = new JTable();
        table.getTableHeader().setReorderingAllowed(false);
        table.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    JTable target = (JTable) e.getSource();
                    int row = target.getSelectedRow();
                    int column = target.getSelectedColumn();
                    if (column == 6) {
                        URL url = null;
                        try {
                            url = new URL("http://".concat(table.getValueAt(
                                    row, column).toString()));
                        } catch (MalformedURLException e1) {

                            e1.printStackTrace();
                        }
                        try {
                            Desktop.getDesktop().browse(url.toURI());
                        } catch (IOException e1) {

                            e1.printStackTrace();
                        } catch (URISyntaxException e1) {

                            e1.printStackTrace();
                        }
                    } else if (column == 7) {
                        @SuppressWarnings("unchecked")
                        String emailS = ((List<String>) table.getValueAt(row,
                                column)).get(0);
                        URI mail = null;
                        try {
                            mail = new URI("mailto:".concat(emailS));
                        } catch (URISyntaxException e1) {

                            e1.printStackTrace();
                        }
                        try {
                            Desktop.getDesktop().mail(mail);
                        } catch (IOException e1) {

                            e1.printStackTrace();
                        }
                    } else {

                        Contact tmpContact = controller.findContactByName(
                                tableModel.getValueAt(row, 0).toString(),
                                tableModel.getValueAt(row, 1).toString());
                        new ContactWindow(2, tmpContact, mainWindow);

                    }
                }
            }
        });

        tableModel = new DefaultTableModel() {

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }

            @Override
            public Class<?> getColumnClass(int column) {
                switch (column) {

                    case 4:
                        return Object.class;
                    case 5:
                        return Object.class;
                    case 7:
                        return Object.class;
                    case 9:
                        return Object.class;
                    case 10:
                        return Object.class;

                    case 11:
                        return Date.class;

                    default:
                        return String.class;
                }
            }

        };
        table.setModel(tableModel);
        tableModel.setDataVector(tableData, columnNames);

        TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(
                table.getModel());

        table.setRowSorter(sorter);

        scrollpane = new JScrollPane(table);
        scrollpane.setBorder(new CompoundBorder(
                new EmptyBorder(10, 10, 10, 10), new BevelBorder(1)));
        display.add(scrollpane);

        JPanel rows = new JPanel();
        rows.setLayout(new BoxLayout(rows, BoxLayout.Y_AXIS));

        JPanel row = new JPanel();
        row.setLayout(new FlowLayout());

        groupFilter = new JTextField(20);
        row.add(groupFilter);
        buttonFilter = new JButton("Group search");
        buttonFilter.addActionListener(groupFilterHandler);
        row.add(buttonFilter);

        rows.add(row);

        row = new JPanel();
        this.fileManager = new JButton("Import/Export from file.");
        this.fileManager.addActionListener(fileManagerHandler);
        row.add(fileManager);
        rows.add(row);
        display.add(rows);

        return display;
    }

    @Override
    public void fillTable(List<Contact> contacts) {
        for (Contact contact : contacts) {
            Vector<Object> contactData = new Vector<Object>();
            contactData.add(contact.getfName());
            contactData.add(contact.getlName());
            contactData.add(contact.gethAddress());
            contactData.add(contact.getcAddress());
            contactData.add(contact.getpPhones());
            contactData.add(contact.getcPhones());
            contactData.add(contact.getHomePage());
            contactData.add(contact.getEmails());
            contactData.add(contact.getPhoto());
            contactData.add(contact.getOthers());
            contactData.add(contact.getGroups());
            contactData.add(contact.getInsertDate());
            tableData.add(contactData);
        }
        tableModel.fireTableDataChanged();

    }

    @Override
    public void addRow(Contact contact) {
        Vector<Object> contactData = new Vector<Object>();
        contactData.add(contact.getfName());
        contactData.add(contact.getlName());
        contactData.add(contact.gethAddress());
        contactData.add(contact.getcAddress());
        contactData.add(contact.getpPhones());
        contactData.add(contact.getcPhones());
        contactData.add(contact.getHomePage());
        contactData.add(contact.getEmails());
        contactData.add(contact.getPhoto());
        contactData.add(contact.getOthers());
        contactData.add(contact.getGroups());
        contactData.add(contact.getInsertDate());

        if (!controller.existsContactByName(contact.getfName(),
                contact.getlName())) {
            tableModel.addRow(contactData);
            controller.addContact(contact.getfName(), contact.getlName(),
                    contact.gethAddress(), contact.getcAddress(),
                    contact.getpPhones(), contact.getcPhones(),
                    contact.getHomePage(), contact.getEmails(),
                    contact.getPhoto(), contact.getOthers(),
                    contact.getGroups(), contact.getInsertDate());

            JScrollBar vertical = scrollpane.getVerticalScrollBar();
            vertical.setValue(vertical.getMaximum());
        }
    }

    @Override
    public synchronized void updateRow(String fNameSource, String lNameSource,
            Contact contact) {
        int row = table.getSelectedRow();

        if (!controller.existsContactByName(contact.getfName(),
                contact.getlName())) {
            tableModel.setValueAt(contact.getfName(), row, 0);
            tableModel.setValueAt(contact.getlName(), row, 1);
            tableModel.setValueAt(contact.gethAddress(), row, 2);
            tableModel.setValueAt(contact.getcAddress(), row, 3);
            tableModel.setValueAt(contact.getpPhones(), row, 4);
            tableModel.setValueAt(contact.getcPhones(), row, 5);
            tableModel.setValueAt(contact.getHomePage(), row, 6);
            tableModel.setValueAt(contact.getEmails(), row, 7);
            tableModel.setValueAt(contact.getPhoto(), row, 8);
            tableModel.setValueAt(contact.getOthers(), row, 9);
            tableModel.setValueAt(contact.getGroups(), row, 10);
            tableModel.setValueAt(contact.getInsertDate(), row, 11);
            tableModel.fireTableDataChanged();

            controller.modifyContact(fNameSource, lNameSource,
                    contact.getfName(), contact.getlName(),
                    contact.gethAddress(), contact.getcAddress(),
                    contact.getpPhones(), contact.getcPhones(),
                    contact.getHomePage(), contact.getEmails(),
                    contact.getPhoto(), contact.getOthers(),
                    contact.getGroups());

        }

    }

    @Override
    public void setController(Controller controller) {
        this.controller = controller;

    }

    @Override
    public void importFile(FileWindow fileWindow, int barNumber, String absolutePath) {
        controller.importFile(fileWindow, barNumber, absolutePath);

    }

    @Override
    public void exportFile(FileWindow fileWindow, int barNumber, String absolutePath) {
        controller.exportFile(fileWindow, barNumber, absolutePath);
    }

    private final class AddContactHandler implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            new ContactWindow(0, new Contact("", ""), mainWindow);
        }
    }

    private final class ViewContactHandler implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            int row = table.getSelectedRow();
            if (row >= 0) {
                Contact tmpContact = controller.findContactByName(tableModel
                        .getValueAt(row, 0).toString(),
                        tableModel.getValueAt(row, 1).toString());
                new ContactWindow(2, tmpContact, mainWindow);
            }
        }
    }

    private final class ModifyContactHandler implements ActionListener {

        public synchronized void actionPerformed(ActionEvent e) {
            int row = table.getSelectedRow();
            if (row >= 0) {
                Contact tmpContact = controller.findContactByName(tableModel
                        .getValueAt(row, 0).toString(),
                        tableModel.getValueAt(row, 1).toString());
                new ContactWindow(1, tmpContact, mainWindow);
            }
        }
    }

    private final class DeleteContactHandler implements ActionListener {

        public synchronized void actionPerformed(ActionEvent e) {
            int row = table.getSelectedRow();
            if (row >= 0) {
                controller.delContact(tableModel.getValueAt(row, 0).toString(),
                        tableModel.getValueAt(row, 1).toString());
                tableModel.removeRow(row);
                tableModel.fireTableRowsDeleted(row, row);
            }
        }
    }

    private final class GroupFilterHandler implements ActionListener {

        public void actionPerformed(ActionEvent e) {

            System.out.println(groupFilter.getText());

            TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(
                    table.getModel());

            RowFilter<TableModel, Object> filter = null;

            try {
                filter = RowFilter.regexFilter(groupFilter.getText(), 10);
            } catch (java.util.regex.PatternSyntaxException e2) {

            }
            sorter.setRowFilter(filter);
            table.setRowSorter(sorter);
        }
    }

    private final class SectionHandler implements ListSelectionListener {

        @Override
        public void valueChanged(ListSelectionEvent arg0) {

            if (sections.getSelectedValue() != null) {
                TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(
                        table.getModel());

                RowFilter<TableModel, Object> filter = null;

                try {
                    filter = RowFilter.regexFilter(
                            "^[".concat(
                                    sections.getSelectedValue().toString()
                                    .toLowerCase()).concat("]"), 1);
                } catch (java.util.regex.PatternSyntaxException e2) {

                }
                sorter.setRowFilter(filter);
                table.setRowSorter(sorter);

            }

        }
    }

    private final class ClearSelectionHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            sections.clearSelection();

            TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(
                    table.getModel());

            RowFilter<TableModel, Object> filter = new RowFilter<TableModel, Object>() {

                @Override
                public boolean include(
                        Entry<? extends TableModel, ? extends Object> arg0) {
                    return false;
                }
            };

            filter = RowFilter.notFilter(filter);

            sorter.setRowFilter(null);
            table.setRowSorter(sorter);

        }
    }

    private final class FileManagerHandler implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            new FileWindow(mainWindow);
        }
    }

}
